/**
 * 
 */
package com.app.framework.orm;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.app.framework.annotations.CascadeRemove;
import com.app.framework.annotations.Save;
import com.app.framework.annotations.TransferInvisible;
import com.app.framework.annotations.Transient;
import com.app.framework.exception.JSONException;
import com.app.framework.exception.ORMException;
import com.app.framework.orm.session.PersistenceSession;
import com.app.framework.orm.session.PersistenceSessionAware;
import com.app.framework.util.IdxUtil;

/**
 * @author lisong
 * @version 2013-4-28 上午10:16:05
 */
public abstract class Collection<T extends CollectionItem> extends ActiveRecord implements PersistenceSessionAware {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4339748080762378033L;

	/**
	 * key为T的uid(主键)
	 */
	@CascadeRemove
	@Save(type="reference")
	private Map<Long,T> items = new HashMap<Long, T>();
	
	@TransferInvisible
	@Transient
	private PersistenceSession persistenceSession;
	
	/**
	 * 获取道具的key 不加载对应的实体类
	 * @return
	 */
	public Set<Long> keySet() {
		
		return items.keySet();
	}
	/**
	 * 获取size 不加载对应的实体类
	 * @return
	 */
	public int size() {
		
		return items.size();
	}
	/**
	 * 是否包含 key 不加载对应实体类
	 * @param key
	 * @return
	 */
	public boolean containsKey(Long key) {
		return items.containsKey(key);
	}
	
	/**
	 * 在集合中添加道具,假如集合中已经有对应的item id,则返回旧的 item对象,否则 返回null
	 * @param item
	 * @return
	 * @throws ORMException
	 */
	public T putItem(T item) throws Exception {
		if(item.getId() == 0l) {
			item.setId(IdxUtil.nextId(item.getClass()));
		}
		item.setCollectionId(id);
		T t = null;
		
		long itemId = item.getId();
		
		t = items.put(itemId, item);
		if(persistenceSession== null) {//new出来的 非cglib
			setItems(items);
		}
		else {
			if(!containsKey(itemId)) {//如果不包含该key 添加 如果包含 key 则不需要修改this
				modifyRefJson(itemId, true);
			}
			persistenceSession.put(item);
		}
		return t;
	}
	/**
	 * 修改从数据库加载上来的json串,目的为减少引用数据读取
	 * @param uid
	 * @param add
	 * @throws JSONException
	 */
	@SuppressWarnings("unchecked")
	private void modifyRefJson(long id,boolean add) throws JSONException {
		List<?> tmp = referenceJson.get("getItems");
		if(tmp != null) {
			List<?> lst = (List<?>) tmp.get(1);
			Map<Long,Long> map = (Map<Long, Long>) lst.get(1);
			if(add) {
				map.put(id, id);
			}else {
				map.remove(id);
			}
			setItems(items);
		}
	}
	
	/**
	 * 移除道具
	 * @param item
	 * @throws ORMException 
	 */
	public void remove(T item) throws Exception {
		modifyRefJson(item.getId(), false);
		persistenceSession.remove(item);
		persistenceSession.put(this);
	}
	
	/**
	 * 移除道具
	 * @param item
	 * @throws ORMException 
	 */
	public void remove(long id,Class<T> clz) throws Exception {
		modifyRefJson(id, false);
		persistenceSession.remove(id,clz);
		persistenceSession.put(this);
	}
	
	/**
	 * 清空集合
	 * @param item
	 * @throws ORMException 
	 */
	public void clear() throws ORMException {
		for(T t : getItems().values()) {	
			persistenceSession.remove(t);
		}
		items.clear();
		setItems(items);
		persistenceSession.put(this);
	}
	public Map<Long, T> getItems() {
		return items;
	}
	
	@SuppressWarnings("unchecked")
	public <E extends StorableModel> E getItem(long id,Class<E> clz) throws Exception {
		if(containsKey(id)) {
			E e = (E) items.get(id);
			if(e == null) {
				return persistenceSession.get(id, clz);
			}
			else {
				return e;
			}
		}
		return null;
	}
	
	public void setItems(Map<Long, T> items) {
		this.items = items;
	}
	
	@Override
	public void setPersistenceSession(PersistenceSession persistenceSession) {
		this.persistenceSession = persistenceSession;
	}
}
